﻿
using CC.Common;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace CC.Extending
{
    /// <summary>
    /// 扩展方法类，存放各种方便好用的扩展方法
    /// </summary>
    public static class ExtenderFunctions
    {

        public static string ToCommaString(this IEnumerable<float> array, char splitor = ';')
        {
            if (array == null || array.Count() <= 0) return "";
            string str = "";
            foreach (var item in array)
            {
                str += splitor.ToString() + item;
            }
            return str.Substring(1);
        }
        public static string ToCommaString(this IEnumerable<ushort> array, char splitor = ';')
        {
            if (array == null || array.Count() <= 0) return "";
            string str = "";
            foreach (var item in array)
            {
                str += splitor.ToString() + item;
            }
            return str.Substring(1);
        }
        public static string ToCommaString(this IEnumerable<short> array, char splitor = ';')
        {
            if (array == null || array.Count() <= 0) return "";
            string str = "";
            foreach (var item in array)
            {
                str += splitor.ToString() + item;
            }
            return str.Substring(1);
        }
        /// <summary>
        /// PointF型数组转成字符串
        /// </summary>
        /// <param name="array"></param>
        /// <param name="splitor">分隔符</param>
        /// <param name="withBrace">输出的字串中是否要括号</param>
        /// <returns></returns>
        public static string ToCommaString(this IEnumerable<Point32> array, char splitor = ';', bool withBrace = true)
        {//因不想在Common类中添加drawing.dll，所以放在这里
            string str = "";
            char innerSplt = splitor == ',' ? ' ' : ',';
            foreach (var item in array)
            {

                str += splitor.ToString() + item.ToCommaString(innerSplt, withBrace);
            }
            return str.Substring(1);
        }
        /// <summary>
        /// 将PointF型数据转换成字符串
        /// </summary>
        /// <param name="point"></param>
        /// <param name="splitor">分隔符</param>
        /// <param name="withBrace">输出的字串中是否要括号</param>
        /// <returns></returns>
        public static string ToCommaString(this Point32 point, char splitor = ',', bool withBrace = true)
        {
            string text = $"{point.X}{splitor}{point.Y}";
            if (withBrace) text = "(" + text + ")";
            return text;
        }
        public static Point32[] TextToPointFArray(this string text, char splitor = ';')
        {
            string[] segs = text.Split(new char[] { splitor }, StringSplitOptions.RemoveEmptyEntries);
            if (segs.Length <= 0) return null;
            Point32[] points = new Point32[segs.Length];
            for (int i = 0; i < points.Length; i++)
            {
                points[i] = segs[i].TextToPointF();
            }

            return points;
        }

        /// <summary>
        /// 将Tuple型数据转换成指定分工符的字符串，可指定是否要括号
        /// </summary>
        /// <param name="point"></param>
        /// <param name="splitor">数据分隔符</param>
        /// <param name="withBrace">是否需要左右括号</param>
        /// <param name="decimalPlace">小数点位置，-1表示不关心</param>
        /// <returns></returns>
        public static string ToCommaString<T>(this (T, T) point, char splitor = ',', bool withBrace = true, int decimalPlace = -1)
        {
            if (decimalPlace < 0)
            {
                string text = $"{point.Item1}{splitor}{point.Item2}";
                if (withBrace) text = "(" + text + ")";
                return text;
            }
            else
            {

                string text1 = point.Item1.ToString();
                string text2 = point.Item2.ToString();
                string text = $"{text1}{splitor}{text2}";
                if (double.TryParse(text1, out double v1) && double.TryParse(text2, out double v2))
                {
                    v1 = Math.Round(v1, decimalPlace);
                    v2 = Math.Round(v2, decimalPlace);
                    text = $"{v1}{splitor}{v2}";
                }
                if (withBrace) text = "(" + text + ")";
                return text;
            }
        }
        public static Point32 TextToPointF(this string text)
        {
            Point32 point = new Point32(0, 0);
            string[] segs = text.Split(new char[] { '(', ',', ' ', ';', ')' }, StringSplitOptions.RemoveEmptyEntries);
            if (float.TryParse(segs.FirstOrDefault(), out float x) && float.TryParse(segs.Last(), out float y))
            {
                point = new Point32(x, y);
            }
            return point;
        }

        /// <summary>
        /// byte[]型数据转换为整型，可选是否低位在前。
        /// </summary>
        /// <param name="array"></param>
        /// <param name="littleEddian">是否低位在前</param>
        /// <returns></returns>
        public static int ByteArrayToInt(this byte[] array, bool littleEddian = true)
        {

            byte[] data = new byte[4];
            if (!littleEddian)
            {
                for (int i = 0; i < 4; i++)
                {
                    if (i < array.Length)
                        data[i] = array[array.Length - i - 1];
                    else
                    {
                        data[i] = 0;
                    }
                }
            }
            else
            {
                for (int i = 0; i < 4; i++)
                {
                    if (i < array.Length)
                        data[i] = array[i];
                    else
                    {
                        data[i] = 0;
                    }
                }

            }
            int num = BitConverter.ToInt32(data, 0);
            return num;
        }
        /// <summary>
        /// 字符串转换成字节数组，支持指定字节长度左或右对齐，并可指定填充字符
        /// </summary>
        /// <param name="text"></param>
        /// <param name="length">字节数组长度。如果长度大于字符数，则按指定的对齐用填充值填充</param>
        /// <param name="leftAlign">是否左对齐，否则是右对齐</param>
        /// <param name="paddingValue">填充值</param>
        /// <returns></returns>
        public static byte[] ToBytes(this string text, int length = 0, bool leftAlign = true, byte paddingValue = 0x00)
        {
            byte[] bytes = Encoding.ASCII.GetBytes(text);
            if (length == 0 || length <= text.Length) return bytes;
            byte[] target = new byte[length];
            if (leftAlign)
            {
                for (int i = 0; i < length; i++)
                {
                    target[i] = i < text.Length ? bytes[i] : paddingValue;
                }
            }
            else
            {
                for (int i = 0; i < length; i++)
                {
                    target[i] = i < length - text.Length ? paddingValue : bytes[length - i];
                }
            }
            return target;
        }

        /// <summary>
        /// 无符号整型转换为byte[]型，并指定是否低位在前
        /// </summary>
        /// <param name="value"></param>
        /// <param name="littleEndian">是否低位在前</param>
        /// <returns></returns>
        public static byte[] ToByteArray(this uint value, bool littleEndian = true)
        {
            byte[] intBytes = BitConverter.GetBytes(value);
            if (BitConverter.IsLittleEndian && !littleEndian)
                Array.Reverse(intBytes);
            return intBytes;
        }
        public static bool ValueEqualTo<T>(this T[] src, T[] targ)
        {

            if (src.Length != targ.Length) return false;
            for (int i = 0; i < src.Length; i++)
            {
                if (!src[i].Equals( targ[i])) return false;
            }
            return true;
        }

        /// <summary>
        /// 16进制字符串转字节数组
        /// </summary>
        /// <param name="hexString"></param>
        /// <returns></returns>
        public static byte[] HexStrToByte(this string hexString)
        {
            hexString = hexString.Replace(" ", "");
            if ((hexString.Length % 2) != 0)
                hexString += " ";
            byte[] returnBytes = new byte[hexString.Length / 2];
            for (int i = 0; i < returnBytes.Length; i++)
                returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);
            return returnBytes;
        }
        public static byte[] Trim(this byte[] src, bool trimLeft, bool trimRight, byte trimByte = 0x00)
        {
            if (src == null || src.Length <= 0) return null;
            int start = 0;
            int stop = src.Length - 1;
            if (trimLeft)
            {
                for (int i = 0; i < src.Length; i++)
                {
                    if (src[i] == trimByte) start = i;
                    else break;//碰到第一个不是剪切字节，则退出循环
                }
            }
            if (trimRight)
            {
                for (int i = src.Length - 1; i >= 0; i--)
                {
                    if (src[i] == trimByte) stop = i;
                    else break;//碰到第一个不是剪切字节，则退出循环
                }
            }
            if (stop - start + 1 == src.Length) return src;
            return src.SubArray(start, stop - start + 1);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="src"></param>
        /// <param name="startIndex"></param>
        /// <param name="length">小于0表示从start到结尾</param>
        /// <returns></returns>
        public static byte[] SubArray(this byte[] src, int startIndex, int length=-1)
        {
            if (length < 0) length = src.Length - startIndex;
            if (src.Length < length + startIndex) return null;
            byte[] targ = new byte[length];
            Array.Copy(src, startIndex, targ, 0, length);
            return targ;
        }

        /// <summary>
        /// 16进制字符串转字节数组
        /// </summary>
        /// <param name="hexString"></param>
        /// <returns></returns>
        public static byte[] HexStrToToByte(this string hexString)
        {
            hexString = hexString.Replace(" ", "");
            if ((hexString.Length % 2) != 0)
                hexString += " ";
            byte[] returnBytes = new byte[hexString.Length / 2];
            for (int i = 0; i < returnBytes.Length; i++)
                returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);
            return returnBytes;
        }
        /// <summary>
        /// 将字节数组输出成16进制字符串
        /// </summary>
        /// <param name="array"></param>
        /// <param name="spliter"></param>
        /// <returns></returns>
        public static string ToHexString(this IEnumerable<byte> array, char spliter = ' ')
        {
            if (array == null || array.Count() <= 0) return "";
            string str = "";
            foreach (var item in array)
            {
                str += spliter.ToString() + item.ToString("X2");
            }
            return str.Substring(1);
        }
        public static short[]ToShortArray(this byte[] src)
        {
            short[] array = new short[src.Length / 2];
            for (int i = 0; i < array.Length; i++)
            {
                array[i] = BitConverter.ToInt16(src, i * 2);
            }
            return array;
        }
        public static ushort[] ToUShortArray(this byte[] src)
        {
            ushort[] array = new ushort[src.Length / 2];
            for (int i = 0; i < array.Length; i++)
            {
                array[i] = BitConverter.ToUInt16(src, i * 2);
            }
            return array;
        }
        /// 整型转换为byte[]型，并指定是否低位在前
        /// </summary>
        /// <param name="value"></param>
        /// <param name="littleEndian">是否低位在前</param>
        /// <returns></returns>
        public static byte[] ToByteArray(this short value, bool littleEndian = true)
        {
            byte[] intBytes = BitConverter.GetBytes(value);
            if (BitConverter.IsLittleEndian && !littleEndian)
                Array.Reverse(intBytes);
            return intBytes;
        }

        /// 整型转换为byte[]型，并指定是否低位在前
        /// </summary>
        /// <param name="value"></param>
        /// <param name="littleEndian">是否低位在前</param>
        /// <returns></returns>
        public static byte[] ToByteArray(this ushort value, bool littleEndian = true)
        {
            byte[] intBytes = BitConverter.GetBytes(value);
            if (BitConverter.IsLittleEndian && !littleEndian)
                Array.Reverse(intBytes);
            return intBytes;
        }

        /// 整型转换为byte[]型，并指定是否低位在前
        /// </summary>
        /// <param name="value"></param>
        /// <param name="littleEndian">是否低位在前</param>
        /// <returns></returns>
        public static byte[] ToByteArray(this int value, bool littleEndian = true)
        {
            byte[] intBytes = BitConverter.GetBytes(value);
            if (BitConverter.IsLittleEndian && !littleEndian)
                Array.Reverse(intBytes);
            return intBytes;
        }
        /// <summary>
        /// 浮点转换为byte[]型，并指定是否低位在前
        /// </summary>
        /// <param name="value"></param>
        /// <param name="littleEndian">是否低位在前</param>
        /// <returns></returns>
        public static byte[] ToByteArray(this float value, bool littleEndian = true)
        {
            byte[] intBytes = BitConverter.GetBytes(value);
            if (BitConverter.IsLittleEndian && !littleEndian)
                Array.Reverse(intBytes);
            return intBytes;
        }
        /// <summary>
        /// 从阵列中取指定索引的元素，索引允许小于0或者超过阵列的单元数
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="array"></param>
        /// <param name="index">不受限索引，允许小于0或大于阵列长度</param>
        /// <returns></returns>
        public static T Fetch<T>(this T[] array, int index)
        {
            
            int legalIndex = EvalLegalIndex(index, array.Length);
            return array[legalIndex];
        }
        /// <summary>
        /// 从阵列中取指定索引的元素，索引允许小于0或者超过阵列的单元数
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="array"></param>
        /// <param name="index">不受限索引，允许小于0或大于阵列长度</param>
        /// <returns></returns>
        public static T Fetch<T>(this IEnumerable<T> array, int index)
        {
            int legalIndex = EvalLegalIndex(index, array.Count());
            return array.ToArray()[legalIndex];
        }
        /// <summary>
        /// 从列表中取指定索引的元素，索引允许小于0或者超过列表的单元数
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list"></param>
        /// <param name="index">不受限索引，允许小于0或大于列表长度</param>
        /// <returns></returns>
        public static T Fetch<T>(this List<T> list, int index)
        {
            int legalIndex = EvalLegalIndex(index, list.Count);
            return list[legalIndex];
        }
        /// <summary>
        /// 计算合法的索引值
        /// 输入不受限的索引和阵列长度，返回合法索引值
        /// </summary>
        /// <param name="index"></param>
        /// <param name="length"></param>
        /// <returns></returns>
        private static int EvalLegalIndex(int index, int length)
        {
            if (index < 0)return EvalLegalIndex(index + length, length);
            else if (index >= length)return EvalLegalIndex(index - length, length);
            else return index;
        }
        /// <summary>
        /// 字符串变换成DateTime
        /// </summary>
        /// <param name="text">支持常规的时间格式以及yyyyMMdd格式</param>
        /// <returns></returns>
        public static DateTime ToDateTime(this string text)
        {
            DateTime res = new DateTime(1989, 6, 4);//纪念某个日子
            int year = 1989;
            int month = 6;
            int day = 4;
            if (DateTime.TryParse(text, out DateTime value))
            {
                res = value;
            }
            else
            {
                if(text.Length>=4)
                {
                    if(int.TryParse(text.Substring(0,4),out int y))
                    {
                        year = y;
                    }
                }
                if (text.Length >= 6)
                {
                    if (int.TryParse(text.Substring(4, 2), out int m))
                    {
                        month = m;
                    }
                }
                if (text.Length >= 8)
                {
                    if (int.TryParse(text.Substring(6, 2), out int d))
                    {
                        day = d;
                    }
                }
                res = new DateTime(year, month, day);
            }
            return res;
        }
       
        /// <summary>
        /// BinaryReader的ReadLine功能
        /// </summary>
        /// <param name="reader"></param>
        /// <returns></returns>
        public static string ReadLine(this BinaryReader reader)
        {
            var result = new StringBuilder();
            char character;
            while ((character = reader.ReadChar()) != '\n')
            {
                if (character != '\r' && character != '\n')
                {
                    result.Append(character);
                }
            }

            return result.ToString();
        }
        /// <summary>
        /// 把一个字符串序列变成以逗号分隔的字符串
        /// </summary>
        /// <param name="array"></param>
        /// <returns></returns>
        public static string ToCommaString<T>(this IEnumerable<T> array)
        {
            string str = "";
            if (array == null || array.Count() <= 0) return "";
            foreach (var a in array)
            {
                str += ", " + a;
            }
            return str.Substring(1).Trim();

        }
        /// <summary>
        /// 把一个字符串序列变成以逗号分隔的字符串
        /// </summary>
        /// <param name="array"></param>
        /// <returns></returns>
        public static string ToCommaString(this IEnumerable< string> array)
        {
            if (array == null || array.Count() <= 0) return "";
            string str = "";
            foreach (var a in array)
            {
                str += ", " + a;
            }
            return str.Substring(1).Trim();
            
        }
        public static List<short> TextToShortArray(this string text)
        {
            List<short> list = new List<short>();
            string[] segs = text.Split(new char[] { ',', ' ', ';', '\t', '，', '；' }, StringSplitOptions.RemoveEmptyEntries);
            foreach (var item in segs)
            {
                if (short.TryParse(item, out short value))
                {
                    list.Add(value);
                }
            }
            return list;
        }

        public static List<float> TextToFloatArray(this string text)
        {
            List<float> list = new List<float>();
            string[] segs = text.Split(new char[] { ',', ' ', ';', '\t','，','；' }, StringSplitOptions.RemoveEmptyEntries);
            foreach (var item in segs)
            {
                if (float.TryParse(item, out float value))
                {
                    list.Add(value);
                }
            }
            return list;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="origin"></param>
        /// <param name="count">+值：顺时针，-值：逆时针</param>
        /// <returns></returns>
        public static T[] Rotate<T>(this T[] origin, int count)
        {
            bool antiClock = count > 0;
            return Rotate(origin, Math.Abs(count), antiClock);
        }
        /// <summary>
        /// 数列旋转。数列首尾相接旋转
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="origin">原始数列</param>
        /// <param name="count">要旋转的索引数</param>
        /// <param name="anticlock">是否逆时针</param>
        /// <returns></returns>
        public static T[] Rotate<T>(this T[] origin,int count,bool anticlock)
        {
            T[] data = new T[origin.Length];
            if(anticlock)
            {

                for (int i = 0; i < origin.Length; i++)
                {
                    if (i < origin.Length - count)
                    {
                        data[i] = origin[origin.Length - count + i];
                    }
                    else
                    {
                        data[i] = origin[i - origin.Length + count];
                    }
                }

            }
            else
            {
                
                for (int i = 0; i < origin.Length; i++)
                {
                    if (i < count)
                    {
                        data[i] = origin[i + origin.Length - count];
                    }
                    else
                    {
                        data[i] = origin[i - origin.Length + count];
                    }
                }
            }
            return data;
        }
        
        public static double[] ToDouble(this float[] floats)
        {
            double[] datas = new double[floats.Length];
            for (int i = 0; i < datas.Length; i++)
            {
                datas[i] = floats[i];
            }
            return datas;
        }
        /// <summary>
        /// 将字符串转换为double型，如果无法转换则返回0
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static double ToDouble(this string s)
        {
            var match = Regex.Match(s, @"^[+-]?Inf", RegexOptions.IgnoreCase);
            if (match.Success)
            {
                if (s.StartsWith("-")) return Single.NegativeInfinity;
                else return float.PositiveInfinity;
            }
            else if (Regex.IsMatch(s, @"^NaN")) return float.NaN;
            else if (double.TryParse(s, out double d))
            {
                return d;
            }
            else return 0;
        }
        /// <summary>
        /// 将字符串转换为double型，如果无法转换则返回0
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static Single ToSingle(this string s)
        {
            var match = Regex.Match(s, @"^[+-]?Inf", RegexOptions.IgnoreCase);
            if (match.Success)
            {
                if (s.StartsWith("-")) return Single.NegativeInfinity;
                else return float.PositiveInfinity;
            }
            else if (Regex.IsMatch(s, @"^NaN")) return float.NaN;
            else if (Single.TryParse(s, out Single d))
            {
                return d;
            }
            else return 0;
        }
        /// <summary>
        /// 将字符串转换为double型，如果无法转换则返回0
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static int ToInt(this string s)
        {
            if (int.TryParse(s, out int d))
            {
                return d;
            }
            else return 0;
        }
        public static bool ToBoolean(this string s)
        {
            if (bool.TryParse(s, out bool d))
            {
                return d;
            }
            else return false;
        }
        /// <summary>
        /// 将字符串转换成浮点数值对。
        /// 支持的数据格式为1,2或(1,2)或(1 2)或去掉括号格式
        /// </summary>
        /// <param name="s">支持的数据格式为1,2或(1,2)或(1 2)或去掉括号格式</param>
        /// <returns>失败时返回null</returns>
        public static Tuple<float,float> ToTupleF(this string s)
        {
            if (string.IsNullOrEmpty(s)) return null;
            string[] sgms = s.Split(new char[] { '(', ')', ',', '，', ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
            //注：分隔符不能用 - 号，因为要识别为负数
            if(Single.TryParse(sgms[0],out float data1)&&Single.TryParse(sgms[1],out float data2))
            {
                return new Tuple<float, float>(data1, data2);
            }
            else
            {
                return null;
            }
        }
        /// <summary>
        /// 将字符串转换成整数数值对。
        /// 支持的数据格式为1,2或(1,2)或(1 2)或去掉括号格式
        /// </summary>
        /// <param name="s">支持的数据格式为1,2或(1,2)或(1 2)或去掉括号格式</param>
        /// <returns>失败时返回null</returns>
        public static Tuple<int, int> ToTupleI(this string s)
        {
            if(string.IsNullOrEmpty(s)) return null;
            string[] sgms = s.Split(new char[] { '(', ')', ',', '，', ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
            if (int.TryParse(sgms[0], out int data1) && int.TryParse(sgms[1], out int data2))
            {
                return new Tuple<int, int>(data1, data2);
            }
            else
            {
                return null;
            }
        }
       
        

        
        
       
    }
}
